package com.free.mini.gateway.function;

import java.util.Map;

import org.reactivestreams.Publisher;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.factory.rewrite.RewriteFunction;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.free.mini.gateway.constants.GatewayConstant;
import com.free.mini.gateway.filter.GatewayContext;
import com.free.mini.gateway.utils.PathWildcardMatchUtil;
import com.free.mini.gateway.utils.SignUtil;
import com.free.mini.gateway.vo.EncryptRequestVO;

import cn.hutool.core.collection.CollectionUtil;
import lombok.extern.log4j.Log4j2;
import reactor.core.publisher.Mono;

/**
 * 解密
 * @author dongsufeng
 * @date 2021/11/9 14:09
 * @version 1.0
 */
@Component
@Log4j2
public class DecryptFunction implements RewriteFunction<String, String> {
	/**
	 * 不需要解密的URL列表
	 */
	@Value("${skip.decrypt.url.list:/api/admin/v1/upload/file}")
	private String skipDecryptUrlList;
	/**
	 * 请求解密：true，false
	 */
	@Value("${request.decode:true}")
	private boolean requestDecode;
	@Value("${gateway.key.private}")
	private String privateKey;

	@Value("${gateway.aes.decrypt.iv}")
	private String iv;

	@Override
	public Publisher<String> apply(ServerWebExchange exchange, String requestVO) {
		log.info("请求解密={}",requestVO);
		try {
			GatewayContext gatewayContext = (GatewayContext) exchange.getAttributes().get(GatewayConstant.CACHE_GATEWAY_CONTEXT);
			if (exchange.getRequest().getMethodValue().equals(HttpMethod.GET.name())){
				return Mono.just(JSON.toJSONString(requestVO));
			}
			log.info("content-type:{}",gatewayContext.getContentType().getType());
			if (!gatewayContext.getContentType().getType().equals(MediaType.APPLICATION_JSON.getType()) ||
					!gatewayContext.getContentType().getSubtype().equals(MediaType.APPLICATION_JSON.getSubtype())){
				return Mono.just(requestVO);
			}
			/**
			 * 跳过请求解密
			 */
			if (!requestDecode || PathWildcardMatchUtil.wildcardMatch(gatewayContext.getURI().getPath(), skipDecryptUrlList)){
				log.warn("GatewayRequestFilter SkipDecrypt: skipDecryptUrl={} ", gatewayContext.getURI().getPath());
				JSONObject jsonObject = JSON.parseObject(requestVO);
				if (jsonObject == null){
					jsonObject = new JSONObject();
				}
				return jsonObject.containsKey("data") ? Mono.just(JSON.toJSONString(jsonObject.get("data"))) : Mono.just(jsonObject.toString());
			}
			EncryptRequestVO encryptRequestVO = JSON.parseObject(requestVO, EncryptRequestVO.class);
			String key = SignUtil.rsaPrivateKeyDecrypt(privateKey, encryptRequestVO.getRandomKey()).strip();
			String requestData = SignUtil.aesDecrypt(iv, key, encryptRequestVO.getData());
			if (!SignUtil.verify(JSON.parseObject(requestData, Map.class))) {
				return Mono.error(new Throwable("验签异常"));
			}
			Map<String, Object> params = gatewayContext.getParams();
			if (CollectionUtil.isNotEmpty(params)){
				JSONObject jsonObject = JSON.parseObject(requestData);
				jsonObject.putAll(params);
				return Mono.just(jsonObject.toString());
			}
			return Mono.just(requestData);
		}catch (Exception e){
			log.error("请求解密异常",e);
			return Mono.error(new Throwable("请求解密异常"));
		}
	}
}
